﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cinch;
using System.ComponentModel;
using MEFedMVVM.ViewModelLocator;
using System.ComponentModel.Composition;

namespace Anata.Client
{
    /// <summary>
    /// Represents a single Image ViewModel
    /// </summary>
    [ExportViewModel("KonsumenViewModel")]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class KonsumenViewModel : EditableValidatingViewModelBase
    {
        #region Data

        private ViewMode currentViewMode = ViewMode.AddMode;

        #region Data.Primitives
        private DataWrapper<Int32> idKonsumen;
        private DataWrapper<String> nama;
        private DataWrapper<String> alamat;
        private DataWrapper<String> telepon;
        private DataWrapper<String> jenisKelamin;
        private DataWrapper<DateTime?> tanggalLahir;

        private bool isBusy = false;
        private KonsumenThumbnailViewModel loadedKonsumenThumbnail;
        private Konsumen loadedKonsumen;
        #endregion

        private IEnumerable<DataWrapperBase> cachedListOfDataWrappers;

        #region Data.Rules
        private static SimpleRule namaRule;
        #endregion

        #region Data.VMs
        #endregion

        #region Data.Services
        private IViewAwareStatus viewAwareStatusService;
        private IMessageBoxService messageBoxService;
        private IUIVisualizerService uiVisualizerService;
        private IKonsumenProvider konsumenProvider;
        private IReferenceProvider referenceProvider;
        #endregion

        #endregion

        #region Constructor
        [ImportingConstructor]
        public KonsumenViewModel(
            IMessageBoxService messageBoxService,
            IUIVisualizerService uiVisualizerService,
            IViewAwareStatus viewAwareStatusService,
            IKonsumenProvider konsumenProvider,
            IReferenceProvider referenceProvider)
	    {
            #region Constructor.SetupServices
            this.messageBoxService = messageBoxService;
            this.uiVisualizerService = uiVisualizerService;
            this.viewAwareStatusService = viewAwareStatusService;
            this.konsumenProvider = konsumenProvider;
            this.referenceProvider = referenceProvider;
            this.viewAwareStatusService.ViewLoaded += ViewAwareStatusService_ViewLoaded;
            #endregion

            #region Constructor.SetupCommands
            KonsumenSaveCommand = new SimpleCommand<Object, Object>(CanExecuteKonsumenSaveCommand, ExecuteKonsumenSaveCommand);
            KonsumenExitCommand = new SimpleCommand<Object, Object>(CanExecuteKonsumenExitCommand, ExecuteKonsumenExitCommand);
            #endregion

            #region Constructor.SetupDataWrappers
            IdKonsumen = new DataWrapper<Int32>(this, idKonsumenChangeArgs);
            IdKonsumen.IsEditable = true;
            Nama = new DataWrapper<String>(this, namaChangeArgs);
            Nama.IsEditable = true;
            Alamat = new DataWrapper<String>(this, alamatChangeArgs);
            Alamat.IsEditable = true;
            Telepon = new DataWrapper<String>(this, teleponChangeArgs);
            Telepon.IsEditable = true;
            JenisKelamin = new DataWrapper<String>(this, jenisKelaminChangeArgs);
            JenisKelamin.IsEditable = true;
            TanggalLahir = new DataWrapper<DateTime?>(this, tanggalLahirChangeArgs);
            TanggalLahir.IsEditable = true;
            #endregion

            //fetch list of all DataWrappers, so they can be used again later without the
            //need for reflection
            cachedListOfDataWrappers =
                DataWrapperHelper.GetWrapperProperties<KonsumenViewModel>(this);

            #region Constructor.SetupValidationRules
            nama.AddRule(namaRule);
            #endregion
			
			#region Constructor.SetupVMs
			#endregion

            Mediator.Instance.Register(this);
	    }
        #endregion

        #region Statics
        static KonsumenViewModel()
        {
            namaRule = new SimpleRule("DataValue", "Nama harus diisi",
                      (Object domainObject)=>
                      {
                          DataWrapper<String> obj = (DataWrapper<String>)domainObject;
                          return obj.DataValue == "";
                      });
        }
        #endregion

        #region Public Properties

        #region Public.Commands
        public SimpleCommand<Object, Object> KonsumenSaveCommand { get; private set; }
        public SimpleCommand<Object, Object> KonsumenExitCommand { get; private set; }
        #endregion

		#region Public.ViewMode
        /// <summary>
        /// The current ViewMode, when changed will loop
        /// through all nested DataWrapper objects and change
        /// their state also
        /// </summary>

        static PropertyChangedEventArgs currentViewModeChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.CurrentViewMode);

        public ViewMode CurrentViewMode
        {
            get { return currentViewMode; }
            set
            {
                currentViewMode = value;

                switch (currentViewMode)
                {
                    case ViewMode.AddMode:
                        this.DisplayName = "Konsumen Baru";
                        break;
                    case ViewMode.EditMode:
                        this.DisplayName = "Ubah Konsumen";
                        break;
                    case ViewMode.ViewOnlyMode:
                        this.DisplayName = "Lihat Konsumen";
                        break;
                }

                //Now change all the CachedListOfDataWrappers
                //Which sets all the Cinch.DataWrapper<T>s to the correct IsEditable
                //state based on the new ViewMode applied to the ViewModel
                //we can use the Cinch.DataWrapperHelper class for this
                DataWrapperHelper.SetMode(
                    CachedListOfDataWrappers,
                    currentViewMode);

                NotifyPropertyChanged(currentViewModeChangeArgs);
            }
        }
        #endregion

		#region Public.Data
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs idKonsumenChangeArgs =
	        ObservableHelper.CreateArgs<KonsumenViewModel>(x => x.IdKonsumen);
        public DataWrapper<Int32> IdKonsumen
        {
	        get { return idKonsumen; }
	        set
	        {
		        idKonsumen = value;
		        NotifyPropertyChanged(idKonsumenChangeArgs);
	        }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs namaChangeArgs =
	        ObservableHelper.CreateArgs<KonsumenViewModel>(x => x.Nama);
        public DataWrapper<String> Nama
        {
	        get { return nama; }
	        set
	        {
		        nama = value;
		        NotifyPropertyChanged(namaChangeArgs);
	        }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs alamatChangeArgs =
	        ObservableHelper.CreateArgs<KonsumenViewModel>(x => x.Alamat);
        public DataWrapper<String> Alamat
        {
	        get { return alamat; }
	        set
	        {
		        alamat = value;
		        NotifyPropertyChanged(alamatChangeArgs);
	        }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs teleponChangeArgs =
            ObservableHelper.CreateArgs<KonsumenViewModel>(x => x.Telepon);
        public DataWrapper<String> Telepon
        {
            get { return telepon; }
            set
            {
                telepon = value;
                NotifyPropertyChanged(teleponChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs jenisKelaminChangeArgs =
            ObservableHelper.CreateArgs<KonsumenViewModel>(x => x.JenisKelamin);
        public DataWrapper<String> JenisKelamin
        {
            get { return jenisKelamin; }
            set
            {
                jenisKelamin = value;
                NotifyPropertyChanged(jenisKelaminChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs tanggalLahirChangeArgs =
            ObservableHelper.CreateArgs<KonsumenViewModel>(x => x.TanggalLahir);
        public DataWrapper<DateTime?> TanggalLahir
        {
            get { return tanggalLahir; }
            set
            {
                tanggalLahir = value;
                NotifyPropertyChanged(tanggalLahirChangeArgs);
            }
        }
        #endregion

        #region Public.IsBusy
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs isBusyChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.IsBusy);
        public bool IsBusy
        {
            get { return isBusy; }
            set
            {
                isBusy = value;
                NotifyPropertyChanged(isBusyChangeArgs);
            }
        }
        #endregion

        #region Public.Cached Collection
        /// <summary>
        /// Returns cached collection of DataWrapperBase
        /// </summary>
        public IEnumerable<DataWrapperBase> CachedListOfDataWrappers
        {
            get { return cachedListOfDataWrappers; }
        }
        #endregion

        #region Public.DataVM
        #endregion

        #endregion

        #region PublicMethods
        public void WorkspaceSave()
        {
            EndEdit();
            IsBusy = true;
            SynchToKonsumen(loadedKonsumen);
            konsumenProvider.LazyUpdateKonsumen(loadedKonsumen, PostSaveKonsumen);
        }
        public void WorkspaceSaveAndExit()
        {
            EndEdit();
            IsBusy = true;
            SynchToKonsumen(loadedKonsumen);
            konsumenProvider.LazyUpdateKonsumen(loadedKonsumen, PostSaveAndExitKonsumen);
        }
        public void WorkspaceExit()
        {
            Mediator.Instance.NotifyColleagues<KonsumenThumbnailViewModel>(
                "DeactivateKonsumenDetail", loadedKonsumenThumbnail);
            this.loadedKonsumen = null;
            this.loadedKonsumenThumbnail = null;
        }
        #endregion

        #region Command Handlers
        /// <summary>
        /// </summary>
        private bool CanExecuteKonsumenSaveCommand(Object args)
        {
            return !isBusy && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteKonsumenSaveCommand(Object args)
        {
            if (IsDirty)
            {
                if (IsValid)
                {
                    WorkspaceSave();
                }
                else
                {
                    //TODO:
                    messageBoxService.ShowError("gagal save, not valid");
                }
            }
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteKonsumenExitCommand(Object args)
        {
            return !isBusy && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteKonsumenExitCommand(Object args)
        {
            if (IsDirty)
            {
                CustomDialogResults result =
                    messageBoxService.ShowYesNoCancel("Simpan perubahan?",
                        CustomDialogIcons.Question);
                if (result == CustomDialogResults.Yes)
                {
                    if (IsValid)
                    {
                        WorkspaceSaveAndExit();
                    }
                    else
                    {
                        //TODO:
                        messageBoxService.ShowError("gagal save, not valid");
                    }
                }
                else if (result == CustomDialogResults.No)
                {
                    //CancelEdit();
                    WorkspaceExit();
                }
                else if (result == CustomDialogResults.Cancel)
                {
                    //do nothing
                }
                else
                {
                    Console.WriteLine("wah2 gawat");
                }
            }
            else
            {
                WorkspaceExit();
            }
        }
        #endregion

        #region MediatorMessageSinks
        [MediatorMessageSink("LoadKonsumenThumbnailToWorkspace")]
        private void LoadKonsumenThumbnailToWorkspace(KonsumenThumbnailViewModel ktvm)
        {
            LoadKonsumenThumbnailInternal(ktvm);
        }

        [MediatorMessageSink("TryCloseKonsumenWorkspace")]
        private void TryCloseKonsumenWorkspace(KonsumenThumbnailViewModel ktvm)
        {
            if (ktvm.Equals(loadedKonsumenThumbnail))
            {
                ExecuteKonsumenExitCommand(null);
            }
        }
        #endregion

        #region PrivateMethods
        #region PrivateMethods.OnViewLoaded
        private void ViewAwareStatusService_ViewLoaded()
        {
            var view = viewAwareStatusService.View;
            IWorkSpaceAware workspaceData = (IWorkSpaceAware)view;
            LoadKonsumenThumbnailInternal((KonsumenThumbnailViewModel)workspaceData.WorkSpaceContextualData.DataValue);
        }
        #endregion

        #region PrivateMethods.Testers
        #endregion

        #region PrivateMethods.Saver
        private void PostSaveKonsumen(Konsumen loadedKonsumen)
        {
            if (loadedKonsumenThumbnail != null && loadedKonsumen != null)
            {
                this.loadedKonsumen = loadedKonsumen;
                ReSynchFromKonsumen(loadedKonsumen);
                SynchToThumbnail(loadedKonsumenThumbnail);
                BeginEdit();
            }
            IsBusy = false;
        }
        private void PostSaveAndExitKonsumen(Konsumen loadedKonsumen)
        {
            if (loadedKonsumenThumbnail != null && loadedKonsumen != null)
            {
                this.loadedKonsumen = loadedKonsumen;
                ReSynchFromKonsumen(loadedKonsumen);
                SynchToThumbnail(loadedKonsumenThumbnail);
                WorkspaceExit();
            }
            IsBusy = false;
        }
        #endregion

        #region PrivateMethods.Loader
        private void LoadKonsumenThumbnailInternal(KonsumenThumbnailViewModel ktvm)
        {
            loadedKonsumenThumbnail = ktvm;
            if (loadedKonsumenThumbnail.IdKonsumen == 0)
            {
                SynchFromThumbnail(ktvm);
                loadedKonsumen = new Konsumen();
                BeginEdit();
            }
            else
            {
                //transaksi lama
                IsBusy = true;
                LoadKonsumen(loadedKonsumenThumbnail.IdKonsumen);
            }
        }

        //background fetching
        private void LoadKonsumen(int idKonsumen)
        {
            konsumenProvider.LazyFetchKonsumen(idKonsumen, PostLoadKonsumen);
        }
        private void PostLoadKonsumen(Konsumen loadedKonsumen)
        {
            if (loadedKonsumenThumbnail != null && loadedKonsumen != null)
            {
                this.loadedKonsumen = loadedKonsumen;
                SynchFromKonsumen(loadedKonsumen);
                SynchToThumbnail(loadedKonsumenThumbnail);
                BeginEdit();
            }
            IsBusy = false;
        }
        #endregion

        #region PrivateMethods.Synchronizer
        private void ReSynchFromKonsumen(Konsumen pKonsumen)
        {
            idKonsumen.DataValue = pKonsumen.IdKonsumen;
        }

        private void SynchFromKonsumen(Konsumen pKonsumen)
        {
            idKonsumen.DataValue = pKonsumen.IdKonsumen;
            nama.DataValue = pKonsumen.Nama;
            alamat.DataValue = pKonsumen.Alamat;
            telepon.DataValue = pKonsumen.NoTelepon;
            jenisKelamin.DataValue = pKonsumen.JenisKelamin;
            tanggalLahir.DataValue = pKonsumen.TanggalLahir;
        }

        private void SynchFromThumbnail(KonsumenThumbnailViewModel ktvm)
        {
            idKonsumen.DataValue = ktvm.IdKonsumen;
            nama.DataValue = ktvm.Nama;
            alamat.DataValue = ktvm.Alamat;
            telepon.DataValue = ktvm.Telepon;
            jenisKelamin.DataValue = ktvm.JenisKelamin;
            tanggalLahir.DataValue = ktvm.TanggalLahir;
        }

        private void SynchToKonsumen(Konsumen pKonsumen)
        {
            pKonsumen.IdKonsumen = idKonsumen.DataValue;
            pKonsumen.Nama = nama.DataValue;
            pKonsumen.Alamat = alamat.DataValue;
            pKonsumen.NoTelepon = telepon.DataValue;
            pKonsumen.JenisKelamin = jenisKelamin.DataValue;
            pKonsumen.TanggalLahir = tanggalLahir.DataValue;
        }

        private void SynchToThumbnail(KonsumenThumbnailViewModel ktvm)
        {
            ktvm.IdKonsumen = idKonsumen.DataValue;
            ktvm.Nama = nama.DataValue;
            ktvm.Alamat = alamat.DataValue;
            ktvm.Telepon = telepon.DataValue;
            ktvm.JenisKelamin = jenisKelamin.DataValue;
            ktvm.TanggalLahir = tanggalLahir.DataValue;
        }
        #endregion

        #endregion

        #region Overrides
        static PropertyChangedEventArgs isValidChangeArgs =
            ObservableHelper.CreateArgs<KonsumenViewModel>(x => x.IsValid);

        public override bool IsValid
        {
            get
            {
                //return base.IsValid and use DataWrapperHelper, if you are
                //using DataWrappers
                return base.IsValid &&
                    DataWrapperHelper.AllValid(cachedListOfDataWrappers);
            }

        }

        static PropertyChangedEventArgs isDirtyChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.IsDirty);
        public bool IsDirty
        {
            get
            {
                return DataWrapperHelper2.SomeDirty(cachedListOfDataWrappers);
            }
        }

        public override string ToString()
        {
            return String.Format("KonsumenViewModel {0}", this.Nama.DataValue);
        }
        #endregion

        #region EditableValidatingViewModelBase overrides
        protected override void OnBeginEdit()
        {
            Console.WriteLine("BEGIN EDIT " + this);
            base.OnBeginEdit();
            //Now walk the list of properties in the OrderViewModel
            //and call BeginEdit() on all Cinch.DataWrapper<T>s.
            //we can use the Cinch.DataWrapperHelper class for this
            DataWrapperHelper.SetBeginEdit(cachedListOfDataWrappers);
        }

        /// <summary>
        /// Override hook which allows us to also put any child 
        /// EditableValidatingViewModelBase objects into the EndEdit state
        /// </summary>
        protected override void OnEndEdit()
        {
            Console.WriteLine("END EDIT " + this);
            base.OnEndEdit();
            //Now walk the list of properties in the OrderViewModel
            //and call CancelEdit() on all Cinch.DataWrapper<T>s.
            //we can use the Cinch.DataWrapperHelper class for this
            DataWrapperHelper.SetEndEdit(cachedListOfDataWrappers);
        }

        /// <summary>
        /// Override hook which allows us to also put any child 
        /// EditableValidatingViewModelBase objects into the CancelEdit state
        /// </summary>
        protected override void OnCancelEdit()
        {
            Console.WriteLine("CANCEL EDIT " + this);
            base.OnCancelEdit();
            //Now walk the list of properties in the OrderViewModel
            //and call CancelEdit() on all Cinch.DataWrapper<T>s.
            //we can use the Cinch.DataWrapperHelper class for this
            DataWrapperHelper.SetCancelEdit(cachedListOfDataWrappers);
        }
        #endregion
    }
}
